package fwhmc.rt;

import fwhmc.rt.exception.RtRuntimeException;
import fwhmc.rt.exception.RtStatusCodeEnum;
import fwhmc.rt.function.BodyBuildFunction;
import fwhmc.rt.function.HeadersBuildFunction;
import fwhmc.rt.function.ParameterBuildFunction;
import fwhmc.rt.function.RequestResultFunction;
import fwhmc.rt.utils.SendEnvironmentType;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.context.ApplicationContext;
import org.springframework.http.*;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import javax.net.ssl.SSLContext;
import java.nio.charset.StandardCharsets;

/**
 * 类描述:  Http通讯请求处理抽象
 *
 * @author 王雷
 * @version 1.0.0
 * @date 2020/7/15 0015 下午 4:03
 */
@Slf4j
public class AbstractHttpRestTemplateManager implements IHttpRestTemplateManager {

    private final ApplicationContext applicationContext;

    protected AbstractHttpRestTemplateManager(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    /**
     * 功能描述：使用Post提交数据
     *
     * @param sendEnvironmentType    提交环境类型
     * @param sendUrl                提交的地址
     * @param requestResultClass     获取后转换的数据对象
     * @param headersBuildFunction   Header构建函数
     * @param bodyBuildFunction      Body构建函数
     * @param parameterBuildFunction 参数构建函数
     * @param sslContext             CA证书拓展
     * @param requestResultFunction  返回结果处理函数
     * @throws RtRuntimeException 自定义运行时异常
     * @author : 王雷
     * @date : 2020/7/15 0015 下午 4:31
     */
    @Override
    public <T, V> V httpByPost(SendEnvironmentType sendEnvironmentType, String sendUrl, Class<T> requestResultClass
            , HeadersBuildFunction headersBuildFunction, BodyBuildFunction bodyBuildFunction
            , ParameterBuildFunction parameterBuildFunction, SSLContext sslContext
            , RequestResultFunction<T, V> requestResultFunction) throws RtRuntimeException {
        return doManager((sendEnvironmentType == null) ? SendEnvironmentType.Internet_Environment : sendEnvironmentType
                , HttpMethod.POST, sendUrl, requestResultClass, headersBuildFunction, bodyBuildFunction
                , parameterBuildFunction, sslContext, requestResultFunction);
    }

    /**
     * 功能描述：使用Post提交数据
     *
     * @param sendUrl                提交的地址
     * @param requestResultClass     获取后转换的数据对象
     * @param headersBuildFunction   Header构建函数
     * @param bodyBuildFunction      Body构建函数
     * @param parameterBuildFunction 参数构建函数
     * @param sslContext             CA证书拓展
     * @param requestResultFunction  返回结果处理函数
     * @throws RtRuntimeException 自定义运行时异常
     * @author : 王雷
     * @date : 2020/7/15 0015 下午 4:31
     */
    @Override
    public <T, V> V httpByPost(String sendUrl, Class<T> requestResultClass, HeadersBuildFunction headersBuildFunction
            , BodyBuildFunction bodyBuildFunction, ParameterBuildFunction parameterBuildFunction, SSLContext sslContext
            , RequestResultFunction<T, V> requestResultFunction) throws RtRuntimeException {

        return httpByPost(null, sendUrl, requestResultClass, headersBuildFunction, bodyBuildFunction
                , parameterBuildFunction, sslContext, requestResultFunction);
    }

    /**
     * 功能描述：使用Get提交数据
     *
     * @param sendEnvironmentType    提交环境类型
     * @param sendUrl                提交的地址
     * @param requestResultClass     获取后转换的数据对象
     * @param headersBuildFunction   Header构建函数
     * @param bodyBuildFunction      Body构建函数
     * @param parameterBuildFunction 参数构建函数
     * @param sslContext             CA证书拓展
     * @param requestResultFunction  返回结果处理函数
     * @throws RtRuntimeException 自定义运行时异常
     * @author : 王雷
     * @date : 2020/7/15 0015 下午 4:31
     */
    @Override
    public <T, V> V httpByGet(SendEnvironmentType sendEnvironmentType, String sendUrl, Class<T> requestResultClass
            , HeadersBuildFunction headersBuildFunction, BodyBuildFunction bodyBuildFunction
            , ParameterBuildFunction parameterBuildFunction, SSLContext sslContext
            , RequestResultFunction<T, V> requestResultFunction) throws RtRuntimeException {
        return doManager((sendEnvironmentType == null) ? SendEnvironmentType.Internet_Environment : sendEnvironmentType
                , HttpMethod.GET, sendUrl, requestResultClass, headersBuildFunction, bodyBuildFunction
                , parameterBuildFunction, sslContext, requestResultFunction);
    }

    /**
     * 功能描述：使用Get提交数据
     *
     * @param sendUrl                提交的地址
     * @param requestResultClass     获取后转换的数据对象
     * @param headersBuildFunction   Header构建函数
     * @param bodyBuildFunction      Body构建函数
     * @param parameterBuildFunction 参数构建函数
     * @param sslContext             CA证书拓展
     * @param requestResultFunction  返回结果处理函数
     * @throws RtRuntimeException 自定义运行时异常
     * @author : 王雷
     * @date : 2020/7/15 0015 下午 4:31
     */
    @Override
    public <T, V> V httpByGet(String sendUrl, Class<T> requestResultClass, HeadersBuildFunction headersBuildFunction
            , BodyBuildFunction bodyBuildFunction, ParameterBuildFunction parameterBuildFunction, SSLContext sslContext
            , RequestResultFunction<T, V> requestResultFunction) throws RtRuntimeException {
        return httpByGet(null, sendUrl, requestResultClass, headersBuildFunction, bodyBuildFunction
                , parameterBuildFunction, sslContext, requestResultFunction);
    }

    /**
     * 功能描述：使用自定义提交数据
     *
     * @param sendEnvironmentType    提交环境类型
     * @param httpMethod             提交的类型
     * @param sendUrl                提交的地址
     * @param requestResultClass     获取后转换的数据对象
     * @param headersBuildFunction   Header构建函数
     * @param bodyBuildFunction      Body构建函数
     * @param parameterBuildFunction 参数构建函数
     * @param sslContext             CA证书拓展
     * @param requestResultFunction  返回结果处理函数
     * @throws RtRuntimeException 自定义运行时异常
     * @author : 王雷
     * @date : 2020/7/15 0015 下午 4:31
     */
    @Override
    public <T, V> V httpByUserDefined(SendEnvironmentType sendEnvironmentType, HttpMethod httpMethod, String sendUrl
            , Class<T> requestResultClass, HeadersBuildFunction headersBuildFunction, BodyBuildFunction bodyBuildFunction
            , ParameterBuildFunction parameterBuildFunction, SSLContext sslContext
            , RequestResultFunction<T, V> requestResultFunction) throws RtRuntimeException {
        return doManager((sendEnvironmentType == null) ? SendEnvironmentType.Internet_Environment : sendEnvironmentType
                , httpMethod, sendUrl, requestResultClass, headersBuildFunction, bodyBuildFunction, parameterBuildFunction
                , sslContext, requestResultFunction);
    }

    /**
     * 功能描述：使用自定义提交数据
     *
     * @param httpMethod             提交的类型
     * @param sendUrl                提交的地址
     * @param requestResultClass     获取后转换的数据对象
     * @param headersBuildFunction   Header构建函数
     * @param bodyBuildFunction      Body构建函数
     * @param parameterBuildFunction 参数构建函数
     * @param sslContext             CA证书拓展
     * @param requestResultFunction  返回结果处理函数
     * @throws RtRuntimeException 自定义运行时异常
     * @author : 王雷
     * @date : 2020/7/15 0015 下午 4:31
     */
    @Override
    public <T, V> V httpByUserDefined(HttpMethod httpMethod, String sendUrl, Class<T> requestResultClass
            , HeadersBuildFunction headersBuildFunction, BodyBuildFunction bodyBuildFunction
            , ParameterBuildFunction parameterBuildFunction, SSLContext sslContext
            , RequestResultFunction<T, V> requestResultFunction) throws RtRuntimeException {
        return httpByUserDefined(null, httpMethod, sendUrl, requestResultClass, headersBuildFunction
                , bodyBuildFunction, parameterBuildFunction, sslContext, requestResultFunction);
    }

    /**
     * 功能描述：使用Post提交数据
     *
     * @param sendEnvironmentType    提交环境类型
     * @param sendUrl                提交的地址
     * @param requestResultClass     获取后转换的数据对象
     * @param headersBuildFunction   Header构建函数
     * @param bodyBuildFunction      Body构建函数
     * @param parameterBuildFunction 参数构建函数
     * @param requestResultFunction  返回结果处理函数
     * @throws RtRuntimeException 自定义运行时异常
     * @author : 王雷
     * @date : 2020/7/15 0015 下午 4:31
     */
    @Override
    public <T, V> V httpByPost(SendEnvironmentType sendEnvironmentType, String sendUrl, Class<T> requestResultClass
            , HeadersBuildFunction headersBuildFunction, BodyBuildFunction bodyBuildFunction
            , ParameterBuildFunction parameterBuildFunction, RequestResultFunction<T, V> requestResultFunction) throws RtRuntimeException {
        return doManager((sendEnvironmentType == null) ? SendEnvironmentType.Internet_Environment : sendEnvironmentType
                , HttpMethod.POST, sendUrl, requestResultClass, headersBuildFunction, bodyBuildFunction
                , parameterBuildFunction, null, requestResultFunction);
    }

    /**
     * 功能描述：使用Post提交数据
     *
     * @param sendUrl                提交的地址
     * @param requestResultClass     获取后转换的数据对象
     * @param headersBuildFunction   Header构建函数
     * @param bodyBuildFunction      Body构建函数
     * @param parameterBuildFunction 参数构建函数
     * @param requestResultFunction  返回结果处理函数
     * @throws RtRuntimeException 自定义运行时异常
     * @author : 王雷
     * @date : 2020/7/15 0015 下午 4:31
     */
    @Override
    public <T, V> V httpByPost(String sendUrl, Class<T> requestResultClass, HeadersBuildFunction headersBuildFunction
            , BodyBuildFunction bodyBuildFunction, ParameterBuildFunction parameterBuildFunction
            , RequestResultFunction<T, V> requestResultFunction) throws RtRuntimeException {
        return httpByPost(null, sendUrl, requestResultClass, headersBuildFunction, bodyBuildFunction
                , parameterBuildFunction, null, requestResultFunction);
    }

    /**
     * 功能描述：使用Get提交数据
     *
     * @param sendEnvironmentType    提交环境类型
     * @param sendUrl                提交的地址
     * @param requestResultClass     获取后转换的数据对象
     * @param headersBuildFunction   Header构建函数
     * @param bodyBuildFunction      Body构建函数
     * @param parameterBuildFunction 参数构建函数
     * @param requestResultFunction  返回结果处理函数
     * @throws RtRuntimeException 自定义运行时异常
     * @author : 王雷
     * @date : 2020/7/15 0015 下午 4:31
     */
    @Override
    public <T, V> V httpByGet(SendEnvironmentType sendEnvironmentType, String sendUrl, Class<T> requestResultClass
            , HeadersBuildFunction headersBuildFunction, BodyBuildFunction bodyBuildFunction
            , ParameterBuildFunction parameterBuildFunction, RequestResultFunction<T, V> requestResultFunction) throws RtRuntimeException {
        return doManager((sendEnvironmentType == null) ? SendEnvironmentType.Internet_Environment : sendEnvironmentType
                , HttpMethod.GET, sendUrl, requestResultClass, headersBuildFunction, bodyBuildFunction
                , parameterBuildFunction, null, requestResultFunction);
    }

    /**
     * 功能描述：使用Get提交数据
     *
     * @param sendUrl                提交的地址
     * @param requestResultClass     获取后转换的数据对象
     * @param headersBuildFunction   Header构建函数
     * @param bodyBuildFunction      Body构建函数
     * @param parameterBuildFunction 参数构建函数
     * @param requestResultFunction  返回结果处理函数
     * @throws RtRuntimeException 自定义运行时异常
     * @author : 王雷
     * @date : 2020/7/15 0015 下午 4:31
     */
    @Override
    public <T, V> V httpByGet(String sendUrl, Class<T> requestResultClass, HeadersBuildFunction headersBuildFunction
            , BodyBuildFunction bodyBuildFunction, ParameterBuildFunction parameterBuildFunction
            , RequestResultFunction<T, V> requestResultFunction) throws RtRuntimeException {
        return httpByGet(null, sendUrl, requestResultClass, headersBuildFunction, bodyBuildFunction
                , parameterBuildFunction, null, requestResultFunction);
    }

    /**
     * 功能描述：使用自定义提交数据
     *
     * @param sendEnvironmentType    提交环境类型
     * @param httpMethod             提交的类型
     * @param sendUrl                提交的地址
     * @param requestResultClass     获取后转换的数据对象
     * @param headersBuildFunction   Header构建函数
     * @param bodyBuildFunction      Body构建函数
     * @param parameterBuildFunction 参数构建函数
     * @param requestResultFunction  返回结果处理函数
     * @throws RtRuntimeException 自定义运行时异常
     * @author : 王雷
     * @date : 2020/7/15 0015 下午 4:31
     */
    @Override
    public <T, V> V httpByUserDefined(SendEnvironmentType sendEnvironmentType, HttpMethod httpMethod, String sendUrl
            , Class<T> requestResultClass, HeadersBuildFunction headersBuildFunction, BodyBuildFunction bodyBuildFunction
            , ParameterBuildFunction parameterBuildFunction, RequestResultFunction<T, V> requestResultFunction) throws RtRuntimeException {
        return doManager((sendEnvironmentType == null) ? SendEnvironmentType.Internet_Environment : sendEnvironmentType
                , httpMethod, sendUrl, requestResultClass, headersBuildFunction, bodyBuildFunction, parameterBuildFunction
                , null, requestResultFunction);
    }

    /**
     * 功能描述：使用自定义提交数据
     *
     * @param httpMethod             提交的类型
     * @param sendUrl                提交的地址
     * @param requestResultClass     获取后转换的数据对象
     * @param headersBuildFunction   Header构建函数
     * @param bodyBuildFunction      Body构建函数
     * @param parameterBuildFunction 参数构建函数
     * @param requestResultFunction  返回结果处理函数
     * @throws RtRuntimeException 自定义运行时异常
     * @author : 王雷
     * @date : 2020/7/15 0015 下午 4:31
     */
    @Override
    public <T, V> V httpByUserDefined(HttpMethod httpMethod, String sendUrl, Class<T> requestResultClass
            , HeadersBuildFunction headersBuildFunction, BodyBuildFunction bodyBuildFunction
            , ParameterBuildFunction parameterBuildFunction, RequestResultFunction<T, V> requestResultFunction) throws RtRuntimeException {
        return httpByUserDefined(null, httpMethod, sendUrl, requestResultClass, headersBuildFunction
                , bodyBuildFunction, parameterBuildFunction, null, requestResultFunction);
    }

    /**
     * 功能描述：执行访问处理
     *
     * @param sendEnvironmentType    提交环境类型
     * @param httpMethod             提交模式，Get或者Post
     * @param sendUrl                提交的地址
     * @param requestResultClass     获取后转换的数据对象
     * @param headersBuildFunction   Header构建函数
     * @param bodyBuildFunction      Body构建函数
     * @param parameterBuildFunction 参数构建函数
     * @param requestResultFunction  返回结果处理函数
     * @param sslContext             CA证书拓展
     * @throws RtRuntimeException 自定义运行时异常
     * @author : 王雷
     * @date : 2020/10/12 0012 上午 11:17
     */
    protected <T, V> V doManager(SendEnvironmentType sendEnvironmentType, HttpMethod httpMethod, String sendUrl
            , Class<T> requestResultClass, HeadersBuildFunction headersBuildFunction, BodyBuildFunction bodyBuildFunction
            , ParameterBuildFunction parameterBuildFunction, SSLContext sslContext
            , RequestResultFunction<T, V> requestResultFunction) throws RtRuntimeException {
        if (httpMethod == null) {
            throw new RtRuntimeException(RtStatusCodeEnum.Code_406.getContent(),
                    RtStatusCodeEnum.Code_406.getContentName(), "无法识别的httpMethod对象!");
        }
        if (sendEnvironmentType == null) {
            throw new RtRuntimeException(RtStatusCodeEnum.Code_406.getContent(),
                    RtStatusCodeEnum.Code_406.getContentName(), "无法识别的sendEnvironmentType对象!");
        }
        try {
            //设置Hearders
            HttpHeaders requestHeaders = new HttpHeaders();
            requestHeaders.setContentType(MediaType.APPLICATION_JSON);
            headersBuildFunction.build(requestHeaders);
            //设置Body
            final Object build = bodyBuildFunction.build();
            HttpEntity<Object> requestEntity;
            if (build != null) {
                requestEntity = new HttpEntity<>(build, requestHeaders);
            } else {
                requestEntity = new HttpEntity<>(requestHeaders);
            }

            //设置参数parameter
            MultiValueMap<String, String> requestParameter = new LinkedMultiValueMap<>();
            parameterBuildFunction.build(requestParameter);

            UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(sendUrl).queryParams(requestParameter);

            RestTemplate restTemplate = null;
            switch (sendEnvironmentType) {
                case Boot_Environment:
                    restTemplate = applicationContext.getBean("restTemplate", RestTemplate.class);
                    break;
                case Internet_Environment:
                    restTemplate = applicationContext.getBean("urlRestTemplate", RestTemplate.class);
                    break;
                default:
                    break;
            }
            if (sslContext != null) {
                //TODO 添加CA证书拓展——待联调测试
                HttpClient client = HttpClients.custom()
                        .setSSLContext(sslContext)
                        .build();
                HttpComponentsClientHttpRequestFactory requestFactory =
                        new HttpComponentsClientHttpRequestFactory();
                requestFactory.setHttpClient(client);
                restTemplate.setRequestFactory(requestFactory);
            }
            restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
            final ResponseEntity<T> responseEntity = restTemplate.exchange(builder.toUriString(), httpMethod, requestEntity, requestResultClass);
            return httpResultManager(requestResultFunction, responseEntity);
        } catch (Exception e) {
            throw new RtRuntimeException(RtStatusCodeEnum.Code_500.getContent(),
                    RtStatusCodeEnum.Code_500.getContentName(), "远程数据链接处理异常!", e);
        }
    }

    /**
     * 功能描述：结果统一处理
     *
     * @author : 王雷
     * @date : 2020/7/15 0015 下午 4:36
     */
    protected <T, V> V httpResultManager(RequestResultFunction<T, V> requestResultFunction, ResponseEntity<T> responseEntity) throws Exception {
        if (!HttpStatus.OK.equals(responseEntity.getStatusCode())) {
            log.error("远程HTTP访问异常：{}", responseEntity);
            throw new RtRuntimeException(responseEntity.getStatusCode().value(),
                    RtStatusCodeEnum.Code_500.getContentName(), "远程HTTP访问异常");
        }
        return requestResultFunction.execute(responseEntity.getBody());
    }
}
